package org.xlp.mvc.bean;

import net.sf.cglib.proxy.MethodProxy;
import org.xlp.bean.base.IBeanCreator;
import org.xlp.bean.base.IBeanWrapper;
import org.xlp.bean.exception.BeanBaseException;
import org.xlp.bean.proxy.AbstractCglibProxy;
import org.xlp.db.tableoption.annotation.XLPTransaction;
import org.xlp.db.utils.XLPDBUtil;
import org.xlp.mvc.util.ClassUtils;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * Service注解对应的bean创建器
 * @see org.xlp.mvc.annotation.Service
 */
public class ServiceAnnotationBeanCreator extends AbstractCglibProxy implements IBeanCreator{
    /**
     * org.xlp.db.tableoption.annotation.XLPTransaction类名称
     * @see org.xlp.db.tableoption.annotation.XLPTransaction
     */
    private static final String XLP_TRANSACTION_CLASS_NAME = "org.xlp.db.tableoption.annotation.XLPTransaction";

    /**
     * 是否加载了org.xlp.db.tableoption.annotation.XLPTransaction类
     */
    private final boolean hasXLPTransactionClass = ClassUtils.hasClass(XLP_TRANSACTION_CLASS_NAME);

    /**
     * 标记目标类类上是否有org.xlp.db.tableoption.annotation.XLPTransaction注解
     */
    private boolean targetClassHasXLPTransaction = false;

    /**
     * 标记目标类上的org.xlp.db.tableoption.annotation.XLPTransaction注解是否需开启事务
     */
    private boolean needTransaction = false;

    /**
     * 构造器
     * @param targetClass bean类型
     * @throws NullPointerException 假如参数为null则抛出该异常
     */
    public ServiceAnnotationBeanCreator(Class<?> targetClass){
        super(targetClass);
        setTargetClassHasXLPTransaction(targetClass);
    }

    /**
     * 构造器
     * @param targetClass bean类型
     * @param classLoader 类加载器
     * @throws NullPointerException 假如第一个参数为null则抛出该异常
     */
    public ServiceAnnotationBeanCreator(Class<?> targetClass, ClassLoader classLoader){
        super(targetClass, classLoader);
        setTargetClassHasXLPTransaction(targetClass);
    }

    private void setTargetClassHasXLPTransaction(Class<?> targetClass){
        if (hasXLPTransactionClass){
            XLPTransaction transaction = targetClass.getAnnotation(XLPTransaction.class);
            this.targetClassHasXLPTransaction = transaction != null;
            needTransaction = targetClassHasXLPTransaction && !transaction.readonly();
        }
    }

    /**
     * 在代理实例上处理方法调用并返回结果
     *
     * @param object
     *            代理对象
     * @param method
     *            被代理的方法
     * @param params
     *            该方法的参数数组
     * @param methodProxy
     * 			     代理方法的MethodProxy对象。每个被代理的方法都对应一个MethodProxy对象
     * @return 方法返回值
     */
    @Override
    public Object intercept(Object object, Method method, Object[] params,
                            MethodProxy methodProxy) throws Throwable {
        // 标记目标方法是否要进行额外的操作
        boolean targetMethodIsExecuteExtraOption = methodNeedExtraOption(object, method, params);
        //判断是否开启事务功能
        boolean isOpenTransaction = isOpenTransaction(method);
        Object value = null;
        try {
            if (isOpenTransaction){
                //开始事务
                XLPDBUtil.beginTransaction();
            }
            //执行目标方法前需要执行的额外逻辑
            if (targetMethodIsExecuteExtraOption){
                ((IBeanWrapper) object).beforeExecute(method, params);
            }
            // 判断方法是否是抽象方法，是跳过执行目标方法
            if (!Modifier.isAbstract(method.getModifiers()) && !getBeanClass().isInterface()){
                value = methodProxy.invokeSuper(object, params);
            }
            //执行目标方法后需要执行的额外逻辑
            if (targetMethodIsExecuteExtraOption){
                ((IBeanWrapper) object).afterExecute(method, params);
            }
            if (isOpenTransaction){
                //提交事务
                XLPDBUtil.commitTransaction();
            }
        } catch (Throwable e) {
            if (isOpenTransaction){
                //事务回滚
                XLPDBUtil.rollbackTransaction();
            }

            //执行抛出异常后需要处理的逻辑
            if (targetMethodIsExecuteExtraOption){
                ((IBeanWrapper) object).throwExecute(method, params, e);
            }
            throw e;
        }
        return value;
    }

    /**
     * 获取目标bean类型
     *
     * @return
     */
    @Override
    @SuppressWarnings("unchecked")
    public <T> Class<T> getBeanClass() {
        return (Class<T>) getTargetClass();
    }

    /**
     * 创建bean对象
     *
     * @return
     * @throws BeanBaseException 假如创建bean实例失败，则抛出该异常
     */
    @Override
    public <T> T createBean() throws BeanBaseException {
        return createProxy();
    }

    /**
     * 判断指定的被代理对象指定的方法是否开启了事务
     *
     * @param method 被代理对象的方法
     * @return
     */
    private boolean isOpenTransaction(Method method){
        if (hasXLPTransactionClass && targetClassHasXLPTransaction){
            XLPTransaction transaction = method.getAnnotation(XLPTransaction.class);
            return needTransaction || (transaction != null && !transaction.readonly());
        }
        return false;
    }
}
